/*查看35行的网址拼接语法，你就知道怎么用了*/
package main
import (
	"fmt"
	"net/http"
	"io/ioutil"
	"errors"
	"regexp"
	"sort"
	"os"
	"runtime"
)
var i int
/**
 * 判断文件是否存在  存在返回 true 不存在返回false
 */
func checkFileIsExist(filename string) bool {
	var exist = true
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		exist = false
	}
	return exist
}

func XieRu(filename string, min int, max int){
	var f *os.File
	if checkFileIsExist(filename) { //如果文件存在
			f, _ = os.OpenFile(filename, os.O_APPEND, 0666) //打开文件
	} else {
			f, _ = os.Create(filename) //创建文件
	}
	defer f.Close()
	
	for j := max; j >= min; j--{
		url := fmt.Sprintf("http://ed2k.com/vod/%d.html", j)	//这里是ed2k网页
		body, err := GetHtml(url)
		if err != nil{
			//fmt.Println(err)
		}
		rt := GetEd2k(body)
		jg := Filtrate(rt)
		for k := 0; k < len(jg); k++{
			f.WriteString(string(jg[k]))
			f.WriteString("\r\n")
			i++
			fmt.Printf("ed2k[%5d] ： %s\n", i, jg[k])
		}
	}
	fmt.Printf("协程 %d - %d 结束！\n", min, max)
}

func main(){
	n := runtime.GOMAXPROCS(1)	//获取CPU核心
	runtime.GOMAXPROCS(n)	//使用最大核心数来处理
	var max = 14140	//要爬取的页面数量
	var xcmax = 100	//要创建的最大协程
	var jl = (max / xcmax) + 1
	for j := 0; j < xcmax; j++{
		filename := fmt.Sprintf("./ed2k-%d.txt", j + 10000)	//为了按顺序排列，这里给文件名加个编号
		go XieRu(filename, j * jl, (j + 1) * jl)
	}
	for{
		runtime.Gosched()
	}
}

/*
* 解析某个string里面的ed2k
* 参数：要解析的string
* 返回值：ed2k内容[][]string
*/
func GetEd2k(body string)(result [][]string){
	reg := regexp.MustCompile("ed2k://[^\"</>]*/")	//ed2k正则表达式规则
	if reg == nil{
		fmt.Println("正则表达式，编译错误：", reg)
		return
	}else{
		result = reg.FindAllStringSubmatch(body, -1)
		return result
	}
}

/*
* []string去重复
* 参数：[]string
* 返回值：去重后的[]string
*/
func Overkill(a []string) (ret []string){
    a_len := len(a)
    for i:=0; i < a_len; i++{
        if (i > 0 && a[i-1] == a[i]) || len(a[i])==0{
            continue;
        }
        ret = append(ret, a[i])
    }
    return ret
}

func Filtrate(str [][]string)(result []string){
	max := len(str)
	sz := make([]string, max)
	for i := 0; i < max; i++{
		sz[i] = fmt.Sprintf("%s", str[i])
	}
	sort.Strings(sz)
	result = Overkill(sz)
	return result
}


/*
* 获取某个url的html代码
* 参数：url地址
* 返回值：string类型，error类型
*/
func GetHtml(url string)(value string, err error){
	resp, err := http.Get(url)
	if err != nil{
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK{
		err = errors.New(fmt.Sprintln("错误代码：",resp.StatusCode))
		return value, err
	}
	all, err := ioutil.ReadAll(resp.Body)
	if err != nil{
		return
	}
	return string(all), nil
}